package fr.umlv.ig.model;

import java.util.ArrayList;
import java.util.List;


/**
 * Represents a line in a metro.
 * Line object is final with a public visibility. You can 
 * modified the object just if you are in his package.
 * @author Jenseric Catbagan
 * @author William Choy
 * 
 */
public class Line {
	/**The id of the Line.*/
	private final String number;
	
	/**The english name of the line.*/
	private final String name;
	
	/**The number of stations in the line*/
	private int numberOfStations;
	
	/**Number of trains in the line*/
	private int numberOfTrains;
	
	/**Number of itineraries in the line*/
	private int numberOfItineraries;
	
	/**List of stations present in the line*/
	private final List<Station> stations = new ArrayList<Station>();
	
	/**List of trains present in the line*/
	private final List<Train> trains = new ArrayList<Train>();
	
	/**List of itinerary present in the line*/
	private final List<Itinerary> itineraries = new ArrayList<Itinerary>();
	
	/**boolean to indicate if the line is selected or not*/
	private boolean isSelected;
	
	/**
	 * Initializes a Line with an id.
	 * @param number the id of the line initialized.
	 */
	public Line(String number) {
		if(number == null) {
			throw new NullPointerException("the number of the line is null");
		}
		name = "Line "+number;
		this.number = number;
	}

	/**
	 * Returns the id of the line.
	 * @return the id of the line.
	 */
	public String getNumber() {
		return number;
	}
	
	/**
	 * Returns the english name of the line.
	 * @return the english name of the line.
	 */
	public String getName() {
		return name;
	}
	
	/**
	 * Returns the number of stations in the line.
	 * @return the number of stations in the line.
	 */
	int getCountStation() {
		return numberOfStations;
	}
	
	/**
	 * Returns the number of trains in the line.
	 * @return the number of trains in the line.
	 */
	int getCountTrain() {
		return numberOfTrains;
	}
	
	/**
	 * Returns the number of itineraries in the line.
	 * @return the number of itineraries in the line.
	 */
	int getCountItinerary() {
		return numberOfItineraries;
	}
	
	/**
	 * Adds a station in the line.
	 * @param station the station to add.
	 * @throws NullPointerException
	 *         the station is null;
	 * @throws IllegalArgumentException
	 *         the station is already in the line.
	 */
	void addStation(Station station) {
		if(station == null ) {
			throw new NullPointerException("The station is null");
		}
		if(stations.contains(station)) {
			throw new IllegalArgumentException("The station is already in the line");
		}
		numberOfStations++;
		stations.add(station);
		//Collections.sort(stations);
	}
	
	
	/**
	 * Returns the station in the index index.
	 * @param index the index to find the station.
	 * @return the station in the index index.
	 */
	Station getStation(int index) {
		if(index< 0 || index> numberOfStations) {
			throw new ArrayIndexOutOfBoundsException();
		}
		return stations.get(index);
	}
	
	/**
	 * Adds a train in the line.
	 * @param train the train to added.
	 * @throws NullPointerException
	 *         the train is null;
	 * @throws IllegalArgumentException
	 *         the train is already in the line.
	 */
	void addTrain(Train train) {
		if(train == null ) {
			throw new NullPointerException("The train is null");
		}
		if(trains.contains(train)) {
			throw new IllegalArgumentException("The train is already in the line");
		}
		numberOfTrains++;
		trains.add(train);
	}
	
	/**
	 * Removes the train on the line.
	 * @param train the train to remove.
	 * @throws NullPointerException
	 *         the train is null;
	 * @throws IllegalArgumentException
	 *         the train is not in the line.
	 */
	void removeTrain(Train train) {
		if(train == null ) {
			throw new NullPointerException("The train is null");
		}
		if(!trains.contains(train)) {
			throw new IllegalArgumentException("The train is not in the line");
		}
		numberOfTrains--;
		trains.remove(train);			
	}
	
	
	/**
	 * Returns the Train in the index index.
	 * @param index the index to find the train.
	 * @return the Train in the index index.
	 */
	Train getTrain(int index) {
		return trains.get(index);
	}
	
	/**
	 * add an itinerary on the line.
	 * @param itinerary the itinerary to add.
	 * @throws NullPointerException
	 *         the itinerary is null;
	 * @throws IllegalArgumentException
	 *         the itinerary is already in the line
	 */
	void addItinaries(Itinerary itinerary) {
		if(itinerary == null) {
			throw new NullPointerException("The itinerary is not in the line");
		}
		if(itineraries.contains(itinerary)) {
			throw new IllegalArgumentException();
		}
		numberOfItineraries++;
		itineraries.add(itinerary);
	}
	
	/**
	 * Returns the {@link Itinerary} in the index.
	 * @param index the index where to find the itinerary.
	 * @return the itinerary in the index in parameter.
	 */
	Itinerary getItinerary(int index) {
		return itineraries.get(index);
	}

	
	@Override
	public boolean equals(Object obj) {
		if(obj == this) {
			return true;
		}
		if(!(obj instanceof Line)) {
			return false;
		}
		Line line = (Line) obj;
		return number.equals(line.number) 
			&& numberOfStations == line.numberOfStations
			&& numberOfTrains== line.numberOfTrains
			&& numberOfItineraries == line.numberOfItineraries; 
	}
	
	@Override
	public int hashCode() {
		return number.hashCode() ^ numberOfItineraries ^ numberOfItineraries ^
			numberOfTrains;
	}

	/**
	 * Returns true if the station is in the line, else false.
	 * @param station the station to check.
	 * @return true if the station is in the line, else false.
	 */
	boolean contains(Station station) {
		return stations.contains(station);
	}
	
//	List<Train> getTrains() {
//		return trains;
//	}
	

	/**
	 * Returns the list of trains present in the Line.
	 * @return the list of trains present in the Line. 
	 */
	List<Train> getTrains() {
		return trains;
	}
	
//	List<Itinerary> getItineraries() {
//		return itineraries;
//	}

	/**
	 * Returns true if the line is selected, else false.
	 * @return true if the line is selected, else false. 
	 */
	public boolean isSelected() {
		return isSelected;
	}

	/**
	 * Sets the boolean which says if the line is selected or not
	 * @param isSelected
	 *        the future boolean  which says if the line will be selected
	 *        or not. 
	 */
	public void setSelected(boolean isSelected) {
		this.isSelected = isSelected;
		
	}

	public boolean contains(Itinerary itinerary) {
		return itineraries.contains(itinerary);
	}

}
